#ifndef AUX_MESSAGEMANAGER_H
#define AUX_MESSAGEMANAGER_H

#include "config.h"
#include <sys/timeb.h>

#include "aux_types.h"
#include "aux_errno.h"
#include "aux_thread.h"
#include "aux_time.h"

#include "aux_queuemanager.h"

#include "aux_message.h"

#define TERMINAL_NAME_LENGTH  (64)
#define MESSAGE_DWORD_DATA_MAX_LENGTH 32

typedef enum {
    LISTEN_TYPE_ALL        = 0,
    LISTEN_TYPE_ID         = 0x1,
    LISTEN_TYPE_NOT_ID     = 0x2,
    LISTEN_TYPE_NAME       = 0x4,
    LISTEN_TYPE_NOT_NAME   = 0x8,
    LISTEN_TYPE_MSG        = 0x10,
    LISTEN_TYPE_NOT_MSG    = 0x20,
} EListenFilterType;

#if 1
typedef enum {
    RECEIVER_FILTER_ALL = 0,
    RECEIVER_FILTER_ID,
    RECEIVER_FILTER_NAME,
    RECEIVER_FILTER_NOT_ID,             /* !(ID)         */
    RECEIVER_FILTER_NOT_NAME,           /* !(NAME)       */
    RECEIVER_FILTER_ID_AND_NAME,        /* (ID && NAME)  */
    RECEIVER_FILTER_ID_OR_NAME,         /* (ID || NAME)  */
    RECEIVER_FILTER_NOT_ID_NOR_NAME,    /* !(ID || NAME) */
    RECEIVER_FILTER_NOT_ID_OR_NOT_NAME  /* !(ID && NAME) */
} EReceiverFilterType;
#endif

typedef enum {
    MESSAGE_ID_UNKOWN = 0,
    MESSAGE_ID_ACK_OK,
    MESSAGE_ID_ACK_WRONG,
    MESSAGE_ID_ACK_DISCONNECT,
    MESSAGE_ID_ACK_INVALID_MSG_TYPE,
    MESSAGE_ID_HEATBEAT,
    /* Router own */
    MESSAGE_ID_QUERY_CLIENT_ID_TO_ROUTER,
    MESSAGE_ID_DELETE_CLIENT_ID_TO_ROUTER,
    MESSAGE_ID_IDENTIFY_CLIENT_SENDER,
    MESSAGE_ID_IDENTIFY_CLIENT_LISTENER,
    MESSAGE_ID_CLIENT_SEND_COMMON_MESSAGE_TO_ROUTER,
    /* Client own */
    MESSAGE_ID_QUERY_CLIENT_ID_OK_TO_CLIENT,
    MESSAGE_ID_ROUTER_SEND_COMMON_MESSAGE_TO_CLIENT,
    MESSAGE_ID_ROUTER_RECEIVED_COMMON_MESSAGE_TO_CLIENT,
    MESSAGE_ID_ROUTER_INVALIDATE_CLIENT_ID_TO_CLIENT,
    MESSAGE_ID_NEED_IDENTIFY_TO_CLIENT,
    MESSAGE_ID_MAX

} ExIPCMessageId;

typedef enum {
    MESSAGE_SRC_TYPE_UNKNOWN    = 0,
    MESSAGE_SRC_TYPE_FROM_ROUTER,
    MESSAGE_SRC_TYPE_FROM_CLIENT,
} EMessageSourceType;

typedef enum {
    MESSAGE_DST_TYPE_UNKNOWN    = 0,
    MESSAGE_DST_TYPE_TO_ROUTER, /* send to router */
    MESSAGE_DST_TYPE_TO_CLIENT, /* send to other client */
    MESSAGE_DST_TYPE_TO_LISTENER, /* send to listener of current client */
    MESSAGE_DST_TYPE_TO_LOCAL_RECVED, /* client gets message from router
                                  router gets message from client */
} EMessageDestinationType;


typedef struct {
    ExIPCMessageId          eMessageId;    /* the id of message */
    EMessageSourceType      eMessageSourceType;  /* type:Router <--> Client */
    EMessageDestinationType eMessageDestinationType;
    u64                     llTimeMsWhenSend; /* time of sending this message */
    u32                     anMessageData[MESSAGE_DWORD_DATA_MAX_LENGTH];
    u32                     nMessageDataDWordCnt;

    u32                  nMessageContTotalCnt; /* total msg count of the full */
    u32                  nMessageContNo; /* the index of msg the client send */

    u32                  nMessageCnt; /* sum of message count sender send */
    /* client use */
    u32                  nClientId;
    char                 szClient[TERMINAL_NAME_LENGTH];
    /* sender use */
    u32                  nIdSender;     /* the sender id of this message */
    char                 szSender[TERMINAL_NAME_LENGTH];
    u32                  nIdReceiverFilter;
    char                 szReceiverFilter[TERMINAL_NAME_LENGTH];
    EReceiverFilterType  eReceiverFilterType;

    u32                  nDataByteCnt;
    void                *pData;   /* data this message owned, malloc create */
} TMessage;

#define isDestinationOutProcess(t) \
    (MESSAGE_DST_TYPE_TO_ROUTER == (t) || MESSAGE_DST_TYPE_TO_CLIENT == (t))

EErrNo xIPC_Msg_DeepCopy(TMessage *ptNew, TMessage *ptOrg);


typedef struct message_listener_t{
    ExIPCMessageId      eMsgId;        /* the msg this listener want */
    u32                 nSenderId;     /* which sender's msg, client id */
    u32                 nListenerId;   /* the id of this listener */
    void               *pListenerData; /* data listener owned, malloc create */
    char                szSender[TERMINAL_NAME_LENGTH];
    char                szReceiver[TERMINAL_NAME_LENGTH];
    EListenFilterType   eListenFilterType;
    union {
        struct message_router_t *ptRouter;
        struct message_client_t *ptClient;
    }                   uOwner;

    struct io_pipe_t        *ptPipe;

    EErrNo        (*pMessageHandler)(struct message_listener_t *, TMessage *);
} TMessageListener;

typedef struct {
    TQueue          tQueueMessage;
    /* use for the increase event of message */
    pthread_mutex_t tQueueMessageIncreaseMutex;
    pthread_cond_t  tQueueMessageIncreaseCond;

    TQueue          tQueueListener;
} TMessageManager;

EErrNo xIPC_Msg_TraverseListener(TMessageManager *ptManager,
                                                          TMessage *ptMessage);

EErrNo xIPC_Msg_AddMessage(TMessageManager *ptManager,
                                                 TMessage *ptMessage);

EErrNo xIPC_Msg_PickMsg(TMessageManager *ptManager,
                                                  TMessage **pptMessage);

EErrNo xIPC_Msg_AddListener(TMessageManager *ptManager,
                                                   TMessageListener *ptData);

EErrNo xIPC_Msg_PickListener(TMessageManager *ptManager,
                                                    TMessageListener **pptData);

EErrNo xIPC_Msg_GetListener(TMessageManager *ptManager,
                                                  TMessageListener **ppData);

EErrNo xIPC_Msg_DeleteListener(TMessageManager *ptManager,
                                                     TMessageListener *pData);

EErrNo xIPC_Msg_WaitForMsg(TMessageManager *ptManager);
EErrNo xIPC_Msg_WaitForMsgTimeout(
                                           TMessageManager *ptManager, u32 nMs);


EErrNo xIPC_Msg_Manager_Init(TMessageManager *ptManager,
                                     const char *pszMsgQueueName,
                                     const char *pszListenerQueueName);

EErrNo xIPC_Msg_Deinit(TMessageManager *ptManager);

EErrNo xIPC_Msg_GetFlattenSize(TMessage *ptMsg, u32 *pnSize);

EErrNo xIPC_Msg_Flatten(TMessage *ptMsg,
                                           void *pBuffer, u32 *pnSize);

EErrNo xIPC_Msg_GetDataSizeFromFlatten(void *pBuffer,
                                                                u32 *pnSize);


EErrNo xIPC_Msg_Embody(TMessage *ptMsg,
                                                   void     *pDataBuffer,
                                                   u32      *pnSize,
                                                   void     *pFlattenBuffer);

EErrNo xIPC_Msg_GetFlattenAuto(TMessage *ptMsg,
                                               void **ppData, u32 *pnSize);
EErrNo xIPC_Msg_PutFlattenAuto(void *pData, u32 nSize);

EErrNo xIPC_Msg_GetMsgTypeFromFlatten(void *pBuffer,
                                                     ExIPCMessageId *peType);

EErrNo xIPC_Msg_GetEmbodyMsgAuto(TMessage *ptMsg,
                                                            void  *pDataBuffer,
                                                            u32 nDataByteCnt);
EErrNo xIPC_Msg_PutEmbodyMsg(TMessage *ptMsg);

EErrNo xIPC_Msg_DeleteAllListener(
                     TMessageManager *ptManager);

EErrNo xIPC_Msg_GetMsgCnt(TMessageManager *ptManager,
                                              u32             *pnCnt);

EErrNo xIPC_Msg_GetFlattenMiniSize(u32 *pnSize);

EErrNo xIPC_Msg_GetDataMaxSize(u32 *pnSize);

#endif

